package session.TX;

import helper.tx.tta.Helper_IPCluster;
import entity.establishment.OutletFood;
import entity.tx.OutletReservation;
import entity.tx.Users;
import entity.tta.DataModel;
import entity.tta.OutletDataModel;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Random;
import javax.ejb.Stateless;
import javax.persistence.Query;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

/**
 *
 * @author Lu Xiaodi
 */
@Stateless
public class ItineraryPlannerSB implements ItineraryPlannerSBRemote {

    @PersistenceContext
    EntityManager em;

    //================Start: methods for cm team itinerary planner=================
    public List<Helper_IPCluster> recommendOutletId(Long userId) {
        // get ageGroupsIdx and countriesIdx
        Users user = em.find(Users.class, userId);
        if (user == null) {
            // throw usernotfound exception
            return null;
        }
        int ageGroupsIdx = this.computeAgeGroupsIdx(user.getBirthDate());
        int countriesIdx = this.computeCountriesIdx(user.getCountry().getCountry());

        // get helper_cluster for all outlet data models (stored in List clusters)
        Query query = em.createQuery("SELECT o FROM OutletDataModel o");
        List<OutletDataModel> allOutletDataModels = query.getResultList();
        List<Helper_IPCluster> allClusters = new ArrayList<Helper_IPCluster>();
        for (OutletDataModel o : allOutletDataModels) {
            OutletFood outlet = em.find(OutletFood.class, o.getOutletId());
            allClusters.add(new Helper_IPCluster(o.getOutletId(), outlet.getStakeholder().getName(),
                    outlet.getOutletName(), o.getCluster()[countriesIdx][ageGroupsIdx]));
        }
        allOutletDataModels = null;

        List<Helper_IPCluster> top50Cluster = this.getTop50(allClusters);

        return top50Cluster;
    }

    private int computeAge(Date birthDate) {
        Calendar birthdate = Calendar.getInstance();
        birthdate.setTime(birthDate);
        Calendar systemTime = Calendar.getInstance();
        systemTime.setTime(new Date());
        int age = systemTime.get(Calendar.YEAR) - birthdate.get(Calendar.YEAR);
        return age;
    }

    /**
     * List of countries:
     * 1. Southeast Asia: Brunei Darussalam, Indonesia, Malaysia, Myanmar, Philippines, Thailand, Vietnam, Other Countries in Southeast Asia
     * 2. North Asia: P R China, Taiwan, Hong Kong SAR, Japan, South Koria, Other Countries in North Asia
     * 3. South Asia: Bangladesh, India, Nepal, Pakistan, Sri Lanka, Other Countries in South Asia
     * 4. West Asia: Iran, Israel, Kuwait, Saudi Arabia, United Arab Emirates, Other Countries in West Asia
     * 5. Europe: Austria, Belgium & Luxembourg, Denmark, Finland, France, Germany, Greece, Italy, Netherlands,
    Norway, Porland, Rep of Ireland, Russian Federation, Spain, Sweden, Switzerland, Turkey, UK, 
    Other Countries in Eastern Europe, Other Countries in Western Europe
     * 6. Occeania: Australia, New Zealand, Other Countries in Oceania
     * 7. Africa: Egypt, Mauritius, South Africa (Rep of), Other Countries in Africa
     * 8. Americas: Canada, USA, other countries in Americas
     */
    private int computeCountriesIdx(String country) {
        OutletDataModel model = new OutletDataModel();
        String[] countries = model.getCountriesArray();
        for (int i = 0; i < countries.length; i++) {
            if (countries[i].trim().equalsIgnoreCase(country)) {
                return i;
            }
        }
        return -1;
    }

    private int computeAgeGroupsIdx(Date birthDate) {
        int age = this.computeAge(birthDate);
        OutletDataModel model = new OutletDataModel();
        String[] ageGroups = model.getAgeGroupsArray();

        for (int i = 0; i < ageGroups.length; i++) {
            String[] ageBoundaries = ageGroups[i].split("-");
            Integer minAge = Integer.parseInt(ageBoundaries[0].trim());
            Integer maxAge = Integer.parseInt(ageBoundaries[1].trim());
            if (minAge <= age && age <= maxAge) {
                return i;
            }
        }
        return -1;
    }

    private List<Helper_IPCluster> getTop50(List<Helper_IPCluster> inputCluster) {
        Collections.sort(inputCluster, Collections.reverseOrder());
        List<Helper_IPCluster> returnList = new ArrayList<Helper_IPCluster>();
        for (int i = 0; i < inputCluster.size(); i++) {
            if (i < 50) {
                returnList.add(inputCluster.get(i));
            }
        }
        for (int i = 0; i<returnList.size();i++){
            returnList.get(i).setSerialNumber(new Long(i)+1);
        }
        return returnList;

//        List<Helper_IPCluster> returnList = new ArrayList<Helper_IPCluster>();
//        //initialize returnList
//        for (int i = 0; i < 50; i++) {
//            returnList.add(new Helper_IPCluster(null, new Long(0)));
//        }
//        //populate returnList
//        for (int i = 0; i < inputCluster.size(); i++) {
//            Helper_IPCluster aCluster = inputCluster.get(i);
//            for (int j = 0; j < returnList.size(); j++) {
//                if (returnList.get(j).getPopularity() <= aCluster.getPopularity()) {
//                    returnList.add(j, aCluster);
//                    returnList.remove(returnList.size() - 1);
//                    break;
//                }
//            }
//        }
//        
//        //finalize returnList, remove dummy elements
//        for (int i = 0 ; i<50; i++){
//            if (returnList.get(i).getPopularity().longValue()==0){
//                for (int j=i; j<50; j++){
//                    //remove the last element
//                    returnList.remove(returnList.size()-1);
//                }
//                break;
//            }
//        }
//        //return result
//        return returnList;
    }
    //=================End: methods for cm team itinerary planner==================

    //==============Start: methods for tcube tta popularity analysis===============
    public List<Helper_IPCluster> getTop50Popular(String country, String ageGroup) {
        List<Helper_IPCluster> allClusters = new ArrayList<Helper_IPCluster>();
        // get helper_cluster for all outlet data models (stored in List clusters)
        Query query = em.createQuery("SELECT o FROM OutletDataModel o");
        List<OutletDataModel> allOutletDataModels = query.getResultList();
        System.out.println("At session bean...");
        System.out.println("SelectedCountry:" + country);
        System.out.println("selectedAgeGroup:" + ageGroup);
        
        if (country.trim().equalsIgnoreCase("all") && ageGroup.trim().equalsIgnoreCase("all")) {
            for (OutletDataModel o : allOutletDataModels) {
                long popularity = 0;
                for (int i = 0; i < o.getCluster().length; i++) {
                    for (int j = 0 ; j < o.getCluster()[0].length; j++){
                        popularity += (long) o.getCluster()[i][j];
                    }
                }
                OutletFood outlet = em.find(OutletFood.class, o.getOutletId());
                allClusters.add(new Helper_IPCluster(o.getOutletId(), outlet.getStakeholder().getName(),
                        outlet.getOutletName(), popularity));
            }
        } else if (country.trim().equalsIgnoreCase("all")) {
            System.out.println("age does not equal to null");
            int ageGroupsIdx = this.computeAgeGroupsIdx(ageGroup);
            for (OutletDataModel o : allOutletDataModels) {
                long popularity = 0;
                for (int i = 0; i < o.getCluster().length; i++) {
                    popularity += (long) o.getCluster()[i][ageGroupsIdx];
                }
                OutletFood outlet = em.find(OutletFood.class, o.getOutletId());
//                System.out.println(popularity);
                allClusters.add(new Helper_IPCluster(o.getOutletId(), outlet.getStakeholder().getName(),
                        outlet.getOutletName(), popularity));
            }
        } else if (ageGroup.trim().equalsIgnoreCase("all")) {
            System.out.println("country does not equal to null");
            int countriesIdx = this.computeCountriesIdx(country);

            for (OutletDataModel o : allOutletDataModels) {
                long popularity = 0;
                for (int i = 0; i < o.getCluster()[0].length; i++) {
                    popularity += (long) o.getCluster()[countriesIdx][i];
                }
                OutletFood outlet = em.find(OutletFood.class, o.getOutletId());
//                System.out.println(popularity);
                allClusters.add(new Helper_IPCluster(o.getOutletId(), outlet.getStakeholder().getName(),
                        outlet.getOutletName(), popularity));
            }
        } else {
            System.out.println("country and age does not equal to null");
            int ageGroupsIdx = this.computeAgeGroupsIdx(ageGroup);
            int countriesIdx = this.computeCountriesIdx(country);

            for (OutletDataModel o : allOutletDataModels) {
                OutletFood outlet = em.find(OutletFood.class, o.getOutletId());
                allClusters.add(new Helper_IPCluster(o.getOutletId(), outlet.getStakeholder().getName(),
                        outlet.getOutletName(), o.getCluster()[countriesIdx][ageGroupsIdx]));
            }
        }
        List<Helper_IPCluster> top50Cluster = this.getTop50(allClusters);
        return top50Cluster.isEmpty() ? null : top50Cluster;
    }

    public String[] getCountriesList() {
        DataModel model = new DataModel();
        String[] countries = model.getCountriesArray();
        return countries;
    }

    public String[] getAgeGroupsList() {
        DataModel model = new DataModel();
        String[] ageGroups = model.getAgeGroupsArray();
        return ageGroups;
    }

    private int getTotalNumCountry() {
        OutletDataModel model = new OutletDataModel();
        String[] countries = model.getCountriesArray();
        return countries.length;
    }

    private int getTotalNumAgeGroup() {
        OutletDataModel model = new OutletDataModel();
        String[] ages = model.getAgeGroupsArray();
        return ages.length;
    }

    private int computeAgeGroupsIdx(String ageGroup) {
        OutletDataModel model = new OutletDataModel();
        String[] ageGroups = model.getAgeGroupsArray();

        for (int i = 0; i < ageGroups.length; i++) {
            if (ageGroups[i].trim().equalsIgnoreCase(ageGroup.trim())) {
                return i;
            }
        }
        return -1;
    }

    //===============End: methods for tcube tta popularity analysis================
    //==========================Start: testing methods=============================
    public void populateOutletReservation() {
        Query query = em.createQuery("SELECT u FROM Users u");
        List<Users> users = query.getResultList();
        Query outletQuery = em.createQuery("SELECT o FROM OutletFood o");
        List<OutletFood> outlets = outletQuery.getResultList();

        Random rm = new Random();
        int numReservations;
        int date;
        int month;
        int outletIdx;
        for (Users u : users) {
            numReservations = rm.nextInt(20);
            for (int i = 0; i < numReservations; i++) {
                outletIdx = rm.nextInt(4);
                OutletFood o = outlets.get(outletIdx);
                date = rm.nextInt(27) + 1;
                month = rm.nextInt(11);
                Calendar c = Calendar.getInstance();
                c.set(2011, month, date);
                OutletReservation or = new OutletReservation();
                or.setCustomer(u);
                or.setCustomerShowUp(rm.nextBoolean());
                or.setOutlet(o);
                or.setTimeslot(c);
                u.addReservation(or);
                o.addReservations(or);
                em.persist(u);
                em.persist(o);
                em.persist(or);
            }
        }
    }

//    public void createUser_Test(String email, String country, int birthYear) {
//        Users user = new Users();
//        user.setEmail(email);
//        user.setCountry(country);
//        Calendar c = Calendar.getInstance();
//        c.set(birthYear, 1, 1);
//        user.setBirthDate(c.getTime());
//        em.persist(user);
//    }

    public List<String> printUser_Test() {
        Query query = em.createQuery("SELECT u FROM Users u");
        List<Users> usersList = query.getResultList();
        List<String> returnList = new ArrayList<String>();
        for (Users u : usersList) {
            returnList.add("UserId:" + u.getId() + "; email:" + u.getEmail()
                    + "; country:" + u.getCountry() + "; birthdate:" + u.getBirthDate());
        }
        return returnList;
    }

    public List<Integer> getCountryAgeIdx(Long cId) {
        Users user = em.find(Users.class, cId);
        Integer countryIdx = this.computeCountriesIdx(user.getCountry().getCountry());
        Integer age = this.computeAge(user.getBirthDate());
        Integer ageIdx = this.computeAgeGroupsIdx(user.getBirthDate());
        List<Integer> returnList = new ArrayList<Integer>();
        returnList.add(countryIdx);
        returnList.add(age);
        returnList.add(ageIdx);
        return returnList;
    }

    public void addNewOutletDataModel_Test(Long outletId) {
        OutletDataModel od = new OutletDataModel();
        od.setOutletId(outletId);
        em.persist(od);
    }

    public void removeNewOutletDataModel_Test() {
        Query query = em.createQuery("SELECT d FROM OutletDataModel d WHERE d.outletId >= 100000 AND d.outletId < 100021");
        List<OutletDataModel> dataModels = query.getResultList();
        for (OutletDataModel aModel : dataModels) {
            em.remove(aModel);
        }
    }

    public List<String> printDataModelByUser(String customerEmail) {
        Query custQuery = em.createQuery("SELECT c FROM Users c WHERE c.email= :email");
        custQuery.setParameter("email", customerEmail);
        List<Users> users = custQuery.getResultList();
        Users selectedUser = users.get(0);

        Query query = em.createQuery("SELECT d FROM OutletDataModel d WHERE d.outletId >= 100000 AND d.outletId < 100021");
        List<OutletDataModel> dataModels = query.getResultList();
        if (dataModels == null || dataModels.isEmpty()) {
            return null;
        }

        int ageIdx = this.computeAgeGroupsIdx(selectedUser.getBirthDate());
        int countryIdx = this.computeCountriesIdx(selectedUser.getCountry().getCountry());

        List<String> returnList = new ArrayList<String>();

        for (int i = 0; i < 20; i++) {
            OutletDataModel aDataModel = dataModels.get(i);
            returnList.add("DataModelId:" + aDataModel.getId() + "; OutletId:" + aDataModel.getOutletId()
                    + "; popularity:" + aDataModel.getCluster()[countryIdx][ageIdx]);
        }
        return returnList;
    }

    public void updateOutletDataModel_Test(String customerEmail) {
        Query custQuery = em.createQuery("SELECT c FROM Users c WHERE c.email= :email");
        custQuery.setParameter("email", customerEmail);
        List<Users> users = custQuery.getResultList();
        Users selectedUser = users.get(0);

        Query query = em.createQuery("SELECT d FROM OutletDataModel d WHERE d.outletId >= 100000 AND d.outletId < 100021");
        List<OutletDataModel> dataModels = query.getResultList();

        int ageIdx = this.computeAgeGroupsIdx(selectedUser.getBirthDate());
        int countryIdx = this.computeCountriesIdx(selectedUser.getCountry().getCountry());

        for (int i = 0; i < 20; i++) {
            OutletDataModel aDataModel = dataModels.get(i);
            aDataModel.getCluster()[countryIdx][ageIdx] = new Long(i);
            em.persist(aDataModel);
        }
    }
    //==========================Start: testing methods=============================
}
